use std::{path::Path, str::FromStr};

use clap::Parser;

#[derive(Debug, Parser)]
pub enum Base64Command {
    #[command(name = "encode", about = "Encode a string to base64...")]
    Encode(Base64EncodeOpts),

    #[command(name = "decode", about = "Decode a string to base64...")]
    Decode(Base64DecodeOpts),
}

#[derive(Debug, Parser)]
pub struct Base64EncodeOpts {
    #[arg(short, long, value_parser = verify_input_file)]
    pub input: String,

    #[arg(short, long, value_parser = parse_format, default_value = "standard")]
    pub format: Base64Format,
}

#[derive(Debug, Parser)]
pub struct Base64DecodeOpts {
    #[arg(short, long)]
    pub input: String,

    #[arg(short, long, value_parser = parse_format, default_value = "standard")]
    pub format: Base64Format,
}

#[derive(Debug, Parser, Clone)]
pub enum Base64Format {
    STANDARD,
    URLSAFE,
}

fn parse_format(format: &str) -> anyhow::Result<Base64Format> {
    format.parse()
}

impl FromStr for Base64Format {
    type Err = anyhow::Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "standard" => Ok(Base64Format::STANDARD),
            "urlsafe" => Ok(Base64Format::URLSAFE),
            _ => Err(anyhow::anyhow!("Unsupported format...")),
        }
    }
}

fn verify_input_file(input: &str) -> anyhow::Result<String> {
    if input == "-" {
        return Ok(input.to_string());
    }

    if Path::new(input).exists() {
        return Ok(input.to_string());
    }

    Err(anyhow::anyhow!("File '{}' does not exist...", input))
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_verify_input_file() {
        let input = "src/cli/base64.rs";
        let result = verify_input_file(input);
        assert!(result.is_ok());
    }
}
